Skip to content

Add additional Prebid debug flags to OpenRTB requests#377

Open
ChristianPavilonis wants to merge 6 commits intomainfrom
feature/additional-prebid-debug-flags
Open

Add additional Prebid debug flags to OpenRTB requests#377
ChristianPavilonis wants to merge 6 commits intomainfrom
feature/additional-prebid-debug-flags

Conversation

@ChristianPavilonis
Copy link
Collaborator

@ChristianPavilonis ChristianPavilonis commented Feb 25, 2026

Summary

Adds debug diagnostics to Prebid/OpenRTB bid requests, surfaces Prebid Server debug response data in the /auction endpoint response, and forwards the real client IP to PBS so bidders see residential rather than data-center traffic.

Changes

New test_mode config param (prebid.rs, config)

Added a separate test_mode config flag that controls the OpenRTB test: 1 field independently from debug. This is intentionally separate because test: 1 signals non-billable traffic and bidders like PubMatic heavily throttle fill (~10% vs ~100%). Defaults to false.

  • debug: true — enables ext.prebid.debug, ext.prebid.returnallbidstatus, debug response metadata, and debug logging
  • test_mode: true — sets test: 1 in the OpenRTB request (defaults to false)

Forward real client IP in device.ip (openrtb.rs, prebid.rs)

Added ip field to the OpenRTB Device struct, populated from DeviceInfo.ip (the real client IP from get_client_ip_addr()). Without this, PBS infers the IP from the incoming connection — a Fastly edge/data-center IP — causing bidders to filter the traffic as non-human (0% fill through Trusted Server).

OpenRTB request debug flags (openrtb.rs, prebid.rs)

When config.debug is enabled, the outgoing OpenRTB request now includes:

{
  "ext": {
    "prebid": {
      "debug": true,
      "returnallbidstatus": true
    }
  }
}
  • ext.prebid.debug: true — enables Prebid Server debug output (httpcalls, resolvedrequest)
  • ext.prebid.returnallbidstatus: true — includes all bid statuses (rejected/no-bid reasons) in the response

All fields are omitted from serialization when debug is disabled (default).

Response debug logging (prebid.rs)

Added log::debug! of the full Prebid Server response JSON in parse_response(), gated on both config.debug and log::log_enabled!(Level::Debug) to avoid wasted serialization.

Debug data in /auction response (prebid.rs)

Extracted enrich_response_metadata() method that attaches Prebid Server response metadata to AuctionResponse.metadata, which flows through ProviderSummaryprovider_details in the /auction response ext:

Always-on fields (present whenever PBS returns them):

  • responsetimemillis — per-bidder response times
  • errors — per-bidder errors
  • warnings — per-bidder warnings (new)

Debug-gated fields (only when config.debug is true):

  • debug — full ext.debug blob (httpcalls, resolvedrequest)
  • bidstatus — per-bid status array from ext.prebid.bidstatus

Safety

  • Startup log::warn! emitted when debug: true is configured, alerting operators that debug data will be included in /auction responses
  • All debug fields default to None/omitted — no behavior change when debug is disabled

Tests

  • to_openrtb_includes_debug_flags_when_enabled — verifies debug flags set without test:1
  • to_openrtb_sets_test_flag_when_test_mode_enabled — verifies test:1 only with test_mode
  • to_openrtb_omits_debug_flags_when_disabled — verifies fields are None and omitted from JSON
  • enrich_response_metadata_attaches_always_on_fields — verifies always-on metadata present, debug-gated fields absent
  • enrich_response_metadata_includes_debug_fields_when_enabled — verifies debug + bidstatus present with correct values

@ChristianPavilonis ChristianPavilonis self-assigned this Feb 25, 2026
@ChristianPavilonis ChristianPavilonis requested review from aram356 and removed request for aram356 February 25, 2026 21:14
@ChristianPavilonis ChristianPavilonis marked this pull request as draft February 25, 2026 21:23
@ChristianPavilonis
Copy link
Collaborator Author

Do we want this in the /auction response, or are debug logs good?
The no bids don't tell us a lot (no headers or anything comes back)

@aram356
Copy link
Collaborator

aram356 commented Feb 26, 2026

Let's return response if prebid integration is enabled with debug = true

@ChristianPavilonis ChristianPavilonis force-pushed the feature/additional-prebid-debug-flags branch from f204475 to 3d752dc Compare February 26, 2026 20:40
@ChristianPavilonis ChristianPavilonis marked this pull request as ready for review February 26, 2026 20:59
PubMatic (and likely other bidders) heavily throttle fill on test:1
traffic (~10% vs ~100%). Previously debug=true set test:1, debug
ext fields, and returnallbidstatus together. Now test:1 is controlled
by a separate test_mode config param so debug diagnostics can be
enabled in production without killing fill rates.
Without this, PBS infers the IP from the incoming connection which is
a Fastly edge/data-center IP. Bidders like PubMatic filter data-center
IPs as non-human traffic, resulting in 0% fill through Trusted Server.
The client IP is already available via get_client_ip_addr() and stored
in DeviceInfo.ip — it just wasn't being passed through to the OpenRTB
Device object.
@ChristianPavilonis
Copy link
Collaborator Author

Investigation: PubMatic no-bid root causes

Debugged why PubMatic was returning 204 (no-bid) on every request through Trusted Server. Found two independent issues:

Issue 1: test: 1 suppresses bidder demand

The debug: true config was setting test: 1 in the OpenRTB request, which signals non-billable test traffic. Tested fill rates by curling PBS directly with identical requests:

Condition PubMatic Fill Rate
Without test: 1 10/10 (100%)
With test: 1 1/10 (10%)

Fix: Decoupled test: 1 into a separate test_mode config param (commit 19c7feb). debug: true still enables ext.prebid.debug and returnallbidstatus for diagnostics.

Issue 2: Fastly edge IP forwarded instead of real client IP

After removing test: 1, PubMatic was still returning 204 through the staging Fastly server (0/10). The OpenRTB Device struct didn't include an ip field, so PBS inferred the IP from the incoming connection — a Fastly data-center IP (157.52.114.28). PubMatic filters data-center IPs as non-human traffic.

The real client IP was already captured in DeviceInfo.ip via get_client_ip_addr() — it just wasn't being passed through to the OpenRTB request.

Fix: Added ip field to the OpenRTB Device struct (commit cb0486f).

Verified on staging

After deploying both fixes to the staging Fastly instance (167.82.82.98):

run 1:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 2:  {"pm_status":204,"pm_ip":"104.12.33.82","bidders":["kargo","mocktioneer"]}
run 3:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 4:  {"pm_status":204,"pm_ip":"104.12.33.82","bidders":["mocktioneer"]}
run 5:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 6:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["kargo","mocktioneer","pubmatic"]}
run 7:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 8:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 9:  {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["mocktioneer","pubmatic"]}
run 10: {"pm_status":200,"pm_ip":"104.12.33.82","bidders":["kargo","mocktioneer","pubmatic"]}

PubMatic fill: 8/10 (80%), up from 0%. Real client IP (104.12.33.82) correctly forwarded in device.ip. Kargo also started bidding.

Additional finding: PubMatic only bids on 300x250

Tested all size combinations against PBS directly. PubMatic adSlot 4407979 (publisher 156229) only has demand for 300x250:

Sizes Fill
970x90, 728x90, 970x250 (header only) 0/5 (0%)
300x250 only 4/5 (80%)
300x250 + 728x90 + 970x90 + 970x250 (in_content) 3/5 (60%)

The header ad slot will never get PubMatic bids since it doesn't include 300x250. This is a PubMatic-side slot configuration issue, not a Trusted Server bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants